# encoding: utf-8
# @File  : nodes.py
# @Author: shaoyun
# @Date  :  2025/05/11
from typing import List, Dict, Any, Optional

from fastapi import APIRouter, Depends, HTTPException, Path
from sqlalchemy.orm import Session
from starlette.status import HTTP_201_CREATED, HTTP_404_NOT_FOUND

from app.api.dependencies import get_current_user, get_db, admin_required
from app.models.user import User
from app.schemas.node import NodeCreate, NodeUpdate, NodeInDB, NodeHeartbeat, NodeStatus
from app.services.ai_optimizer import ai_optimizer
from app.services.node_manager import NodeManager
from app.models.node import Node, NodeStatus
from app.core.response import get_response
from app.core.status_codes import SUCCESS
router = APIRouter()


@router.post("/register", response_model=NodeInDB, status_code=HTTP_201_CREATED)
async def register_node(
        node_in: NodeCreate,
        db: Session = Depends(get_db),
        current_user: User = Depends(admin_required)
):
    """注册新节点（仅管理员）"""
    node = await NodeManager.register_node(
        db=db,
        name=node_in.name,
        host_ip=node_in.host_ip,  # 新增 host_ip 参数
        ip=node_in.ip,
        port=node_in.port,
        is_master=node_in.is_master,
        description=node_in.description
    )

    # 将DB模型转换为Pydantic模型
    return NodeInDB(
        id=node.id,
        name=node.name,
        host_ip=node.host_ip,  # 新增 host_ip 到返回模型
        ip=node.ip,
        port=node.port,
        is_master=node.is_master,
        status=node.status.value,
        cpu_usage=node.cpu_usage,
        memory_usage=node.memory_usage,
        description=node.description,
        created_at=node.created_at,
        updated_at=node.updated_at,
        last_heartbeat=node.last_heartbeat
    )


@router.get("/list", response_model=Dict[str, Any])  # 修改返回类型
async def get_nodes(
        status: Optional[str] = None,
        skip: int = 0,
        limit: int = 100,
        db: Session = Depends(get_db),
        current_user: User = Depends(get_current_user)
):
    """获取节点列表"""
    nodes = await NodeManager.get_nodes(
        db=db,
        status=status,
        skip=skip,
        limit=limit
    )

    # 将DB模型转换为Pydantic模型
    node_list = [
        NodeInDB(
            id=node.id,
            name=node.name,
            host_ip=node.host_ip,
            ip=node.ip,
            port=node.port,
            is_master=node.is_master,
            status=node.status.value,
            cpu_usage=node.cpu_usage,
            memory_usage=node.memory_usage,
            description=node.description,
            created_at=node.created_at,
            updated_at=node.updated_at,
            last_heartbeat=node.last_heartbeat
        )
        for node in nodes
    ]

    # 获取总数
    query = db.query(Node)
    if status:
        try:
            node_status = NodeStatus(status)
            query = query.filter(Node.status == node_status)
        except ValueError:
            pass
    total = query.count()
    data = {
            "items": node_list,
            "total": total,
            "page": (skip // limit) + 1,
            "limit": limit
        }

    return get_response(SUCCESS, data=data)

@router.get("/{node_id}/detail", response_model=NodeInDB)
async def get_node(
        node_id: str = Path(...),
        db: Session = Depends(get_db),
        current_user: User = Depends(get_current_user)
):
    """获取节点详情"""
    node = await NodeManager.get_node(db=db, node_id=node_id)

    if not node:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="Node not found"
        )

    # 将DB模型转换为Pydantic模型
    return NodeInDB(
        id=node.id,
        name=node.name,
        host_ip=node.host_ip,
        ip=node.ip,
        port=node.port,
        is_master=node.is_master,
        status=node.status.value,
        cpu_usage=node.cpu_usage,
        memory_usage=node.memory_usage,
        description=node.description,
        created_at=node.created_at,
        updated_at=node.updated_at,
        last_heartbeat=node.last_heartbeat
    )


@router.put("/{node_id}/update", response_model=NodeInDB)
async def update_node(
        node_update: NodeUpdate,
        node_id: str = Path(...),
        db: Session = Depends(get_db),
        current_user: User = Depends(admin_required)
):
    """更新节点（仅管理员）"""
    node = await NodeManager.get_node(db=db, node_id=node_id)

    if not node:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="Node not found"
        )

    # 更新节点字段
    if node_update.name is not None:
        node.name = node_update.name

    if node_update.ip is not None:
        node.ip = node_update.ip

    if node_update.port is not None:
        node.port = node_update.port

    if node_update.status is not None:
        from app.models.node import NodeStatus as NodeStatusEnum
        try:
            new_status = NodeStatusEnum(node_update.status)
            node.status = new_status
        except ValueError:
            raise HTTPException(
                status_code=400,
                detail=f"Invalid status value: {node_update.status}"
            )

    if node_update.description is not None:
        node.description = node_update.description

    if node_update.cpu_usage is not None:
        node.cpu_usage = node_update.cpu_usage

    if node_update.memory_usage is not None:
        node.memory_usage = node_update.memory_usage

    db.commit()
    db.refresh(node)

    # 将DB模型转换为Pydantic模型
    return NodeInDB(
        id=node.id,
        name=node.name,
        host_ip=node.host_ip,
        ip=node.ip,
        port=node.port,
        is_master=node.is_master,
        status=node.status.value,
        cpu_usage=node.cpu_usage,
        memory_usage=node.memory_usage,
        description=node.description,
        created_at=node.created_at,
        updated_at=node.updated_at,
        last_heartbeat=node.last_heartbeat
    )


@router.post("/{node_id}/heartbeat", response_model=Dict[str, Any])
async def update_heartbeat(
        heartbeat: NodeHeartbeat,
        db: Session = Depends(get_db)
):
    """更新节点心跳（无需身份验证，由节点自身调用）"""
    # 验证节点ID是否匹配
    if heartbeat.node_id != heartbeat.node_id:
        raise HTTPException(
            status_code=400,
            detail="Node ID mismatch"
        )

    success = await NodeManager.update_node_heartbeat(db, heartbeat.node_id)

    if not success:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="Node not found"
        )

    return {"success": True, "timestamp": heartbeat.timestamp}


@router.post("/{node_id}/status", response_model=Dict[str, Any])
async def update_node_status(
        status: NodeStatus,
        db: Session = Depends(get_db)
):
    """更新节点状态（无需身份验证，由节点自身调用）"""
    # 验证节点ID是否匹配
    if status.node_id != status.node_id:
        raise HTTPException(
            status_code=400,
            detail="Node ID mismatch"
        )

    success = await NodeManager.update_node_workload(
        db=db,
        node_id=status.node_id,
        cpu_usage=status.cpu_usage,
        memory_usage=status.memory_usage
    )

    if not success:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="Node not found"
        )

    # 检测是否有异常
    is_anomaly, message = await ai_optimizer.detect_anomaly(
        node_id=status.node_id,
        metrics={
            "cpu_usage": status.cpu_usage,
            "memory_usage": status.memory_usage,
            "load_average": status.load_average,
            "disk_usage": status.disk_usage,
            "timestamp": status.timestamp
        }
    )

    return {
        "success": True,
        "timestamp": status.timestamp,
        "is_anomaly": is_anomaly,
        "message": message if is_anomaly else ""
    }


@router.post("/{node_id}/disable", response_model=Dict[str, Any])
async def disable_node(
        node_id: str = Path(...),
        db: Session = Depends(get_db),
        current_user: User = Depends(admin_required)
):
    """禁用节点（仅管理员）"""
    success = await NodeManager.disable_node(db, node_id)

    if not success:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="Node not found"
        )

    return {"success": True, "message": "Node disabled successfully"}


@router.post("/{node_id}/enable", response_model=Dict[str, Any])
async def enable_node(
        node_id: str = Path(...),
        db: Session = Depends(get_db),
        current_user: User = Depends(admin_required)
):
    """启用节点（仅管理员）"""
    success = await NodeManager.enable_node(db, node_id)

    if not success:
        raise HTTPException(
            status_code=HTTP_404_NOT_FOUND,
            detail="Node not found"
        )

    return {"success": True, "message": "Node enabled successfully"}